#include "RtspClientStream.h"
#include "mediaPriv.h"
#include "VideoDecode.h"

namespace Media{

 std::map<int, RtspClientStream *> RtspClientStream::sm_streamMap;
 std::recursive_mutex 		      RtspClientStream::sm_mapMutex;


std::recursive_mutex g_stream_creater_mux;
static FrameCommon::StreamPlayCreater::Ptr g_stream_creater;

void SetMediaStreamCreater(FrameCommon::StreamPlayCreater::Ptr creater){
    std::lock_guard<std::recursive_mutex> lock(g_stream_creater_mux);
    g_stream_creater = creater;
}

FrameCommon::StreamPlayCreater::Ptr GetStreamCreater(){
    return g_stream_creater;
}

static FrameCommon::StreamPlayer::Ptr GetPlayer(const std::string& stream_url, 
        bool isRtspTcp = false){
    tracef("RtspClientStream  GetPlayer stream_url %s", stream_url.c_str());
    std::lock_guard<std::recursive_mutex> lock(g_stream_creater_mux);
    FrameCommon::StreamPlayer::Ptr streamPtr;
    if(g_stream_creater){
        streamPtr = g_stream_creater->CreateStreamPlayer(stream_url, isRtspTcp);
    }
    return streamPtr;
}

RtspClientStream *RtspClientStream::GetInstance(int channel){
    std::lock_guard<std::recursive_mutex> guard(sm_mapMutex);
    
	if(sm_streamMap.find(channel) == sm_streamMap.end())
	{
		return nullptr;
	}
    return sm_streamMap[channel];
}

RtspClientStream *RtspClientStream::instance(int channel)
{
    std::lock_guard<std::recursive_mutex> guard(sm_mapMutex);
    
	if(sm_streamMap.find(channel) == sm_streamMap.end())
	{
		sm_streamMap[channel] = new RtspClientStream(channel);
	}

	return sm_streamMap[channel];
}


RtspClientStream::RtspClientStream(int channel) 
{   
    m_taskTimer.reset();
    m_channel = channel;

    m_streamInThread.start([this](Fdt::Thread *thread){this->StreamInProc(thread);}); //启动单独线程处理流
}

bool RtspClientStream::setFormat(VideoDecFormat *format)
{
    if(!format || !m_pVideoDecode)
	{
	    errorf("format or m_videoDecoder is NULL \n");
		return false;
	}
		
    return m_pVideoDecode->setFormat(format);
}

bool RtspClientStream::start(StreamPlayInfo playInfo)
{	
     LOG_PrintWarn("m_channel=%d, type=%d, streamInfo=%s, playAbility=%d, audioChn=%d, videoChn=%d\n",
                m_channel, playInfo.stream.type,playInfo.stream.content, playInfo.playAbility, playInfo.audioChn, playInfo.videoChn);
    if(!m_started)
    { 
        m_playAbility = playInfo.playAbility;
        
        ///创建视频解码并启动
        if((m_playAbility == VIDEO_AUDIO) || (m_playAbility == VIDEO_ONLY))
        {
            if(m_videoChannel != playInfo.videoChn)
            {            
                m_videoChannel = playInfo.videoChn;
                m_pVideoDecode = VideoDecode::instance(m_videoChannel); 
            }
            if(!m_pVideoDecode)
            {
                errorf("m_videoDecoder is NULL \n");
                return false;
            }

            VideoDecFormat decFormat;
            memset(&decFormat, 0, sizeof(VideoDecFormat));
            decFormat.type = videoEncH264;
            if(!m_pVideoDecode->setFormat(&decFormat))
            {
                errorf("m_pVideoDecode setFormat failed\n");
                return false;
            }
            
            if(!m_pVideoDecode->start())
            {
                errorf("m_pVideoDecode start failed\n");
                return false;
            }
        }

        ///创建音频输入管理对象
        if((m_playAbility == VIDEO_AUDIO) || (m_playAbility == AUDIO_ONLY))
        {
            if(m_audioChannel != playInfo.audioChn)
            {            
                m_audioChannel = playInfo.audioChn;
                m_pAudioDecode = AudioDecode::instance(m_audioChannel);
            }
            if(!m_pAudioDecode)
            {
                errorf("m_pAudioDecode is NULL \n");
                return false;
            }

            AudioDecFormat decFormat = {0};
            decFormat.type = audioEncAAC;
            decFormat.frequency = 48000;
    	    decFormat.depth = 16; //todo   
    	    decFormat.channels = 2;
            
            if(!m_pAudioDecode->setFormat(&decFormat))
            {
                errorf("AudioDecode setFormat error\n");
                return false;
            }
            
			if(!m_pAudioDecode->start())
            {
                errorf("AudioDecode start error\n");
                return false;
            }
        }

        ///创建RTSP服务
        m_rtspUrl = playInfo.stream.content;
        m_streamClient = GetPlayer(m_rtspUrl, true);
        if(!m_streamClient) return false;

        ///按任务启动流
        m_taskInfo = playInfo.task;
    	m_taskTimer.reset(new Fdt::Timer(m_taskInfo.StartTime * 1000, ([this](){return this->streamStart();}), nullptr));
    	
    	m_started = true;

    	m_dropFrame = true;
    }
  
	return true;
}

bool RtspClientStream::stop()
{
	if(m_started)
    {
        streamStop();

        if((m_playAbility == VIDEO_AUDIO) || (m_playAbility == VIDEO_ONLY))
        {
            if (!m_pVideoDecode || !m_pVideoDecode->stop())
        	{
        		return false;
        	}
    	}

    	if((m_playAbility == VIDEO_AUDIO) || (m_playAbility == AUDIO_ONLY))
        {
            if (!m_pAudioDecode || !m_pAudioDecode->stop())
        	{
        		return false;
        	}
    	}    	
    	m_started = false;
        m_queueMutex.lock();
        while(!m_frameaQueue.empty()) m_frameaQueue.pop();
        m_queueMutex.unlock();
    }

    clearVideoQueue();

    m_dropFrame = false;

	return true;
}

bool RtspClientStream::clearVideoQueue()
{
    m_queueMutex.lock();
    while(!m_frameaQueue.empty()) m_frameaQueue.pop();
    m_queueMutex.unlock();

    return true;
}

bool RtspClientStream::SaveToCommQueue(FramePtr& msg)
{
	if(msg.get() != NULL && m_frameaQueue.size() < QueueSize)
	{
		m_queueMutex.lock();

	    m_frameaQueue.push(msg);

		m_queueMutex.unlock();
	}
	else
	{
	    m_queueMutex.lock();
	    m_frameaQueue.front();//处理队列中消息,移除最早的数据	
    	m_frameaQueue.pop();
    	m_queueMutex.unlock();
	    //printf("enter [%s] [%d] size=%d\n",__FILE__,__LINE__, m_frameaQueue.size());
	}
	return true;
}

bool RtspClientStream::GetCommQueueMsg(FramePtr& msg)
{
	m_queueMutex.lock();
	if(!m_frameaQueue.empty())
	{	    
    	msg = m_frameaQueue.front();//处理队列中消息		
    	m_frameaQueue.pop();
	
    	//printf("enter [%s] [%d] \n",__FILE__,__LINE__);
    	m_queueMutex.unlock();
    	return true;
	}
	m_queueMutex.unlock();
	return false;
}

void RtspClientStream::StreamInProc(Fdt::Thread *thread)
{
    thread->setPriority(Fdt::PRIORITY_NORMAL, Fdt::POLICY_RR); 

    //printf("enter [%s] [%d] \n",__FILE__,__LINE__);

    uint64_t lastTime = vdo_get_time();

    int      frameProcTime = 30;

    int      disConnTime   = 1000;

#if 1
    FramePtr framePtr;
    
    while(thread->running())
    {
        if(!GetCommQueueMsg(framePtr))
        {
            thread->sleep(3);
            continue;
        }

        //media_FILE_Write("/extern/rtsp.h264", framePtr->data, framePtr->size);
        
        sendVideoPacket(framePtr->data, framePtr->size, framePtr->timestamp);

        uint64_t runtime = vdo_get_time() - lastTime;
        if(runtime < frameProcTime)
        {
            thread->sleep(frameProcTime - runtime);
        }
        else if(runtime > disConnTime) //?????????
        {
            thread->sleep(frameProcTime);

            //LOG_PrintWarn("ScreenMirrorStream ::StreamInProc  over maxFreq runtime=%llu, maxFreq=%u\n", runtime, maxFreq);
        }

        

        lastTime = vdo_get_time();
  
    }
#endif   
}

bool RtspClientStream::onFrame(const FrameCommon::Frame::Ptr &frame)
{
    //tracef("m_rtspUrl:%s, frame------>type:%d, isVideo:%d, size %d", m_rtspUrl.c_str(), frame->getTrackType(), frame->isVideo(), frame->size());   
    if(frame->isVideo())
    {
    #if 1

        char *data = frame->data();
        if(m_dropFrame && frame->size() > 4)
        {
            int frameType = data[4] & 0x1F;          
            if(0x07 == frameType ) //|| 0x05 == data[4] || 0x08 == data[4]
            {
                LOG_PrintWarn("RtspClientStream:: m_channel=%d,m_rtspUrl:%s, video keyFrame=%d, data[4]=%02x \n",m_channel,  m_rtspUrl.c_str(), frame->keyFrame(), data[4]);

                m_dropFrame = false;               
            }
            else
            {
                LOG_PrintWarn("RtspClientStream:: Frameerror not I frame ,m_rtspUrl:%s, data[4]=%02x\n", m_rtspUrl.c_str(), data[4]); 
                return true;
            } 
        }
    #endif  

            FramePtr videoFrame(new FrameBuffer(frame->size()));
            videoFrame->timestamp = frame->pts();
            videoFrame->size = frame->size();
            memcpy(videoFrame->data, frame->data(), frame->size());
            SaveToCommQueue(videoFrame);
         
    }
    else if(frame->isAudio())
    {
        sendAudioPacket((unsigned char *)frame->data(), frame->size());
        
    }
    
    return true;
}


bool RtspClientStream::onStop()
{
	tracef("onStop");
	return true;
}

void RtspClientStream::SetDirectFrameCallBack(const FrameCommon::frame_callback_func callback){
    m_frame_call_back = callback;
}

bool RtspClientStream::streamStart()
{
    m_streamClient->Start([this](const FrameCommon::Frame::Ptr &frame){ onFrame(frame);}, 
        [this](){ onStop(); });
    if(m_taskInfo.StopTime != -1)
    {
        m_taskTimer.reset(new Fdt::Timer(m_taskInfo.StopTime * 1000, ([this](){return this->stop();}), nullptr)); //不是循环播放，注册停止函数
    }
    else
    {
        m_taskTimer.reset();
    }
    
    return true;
}

	
bool RtspClientStream::streamStop(void)
{
    m_streamClient->Stop();
    return true;
}


bool RtspClientStream::sendVideoPacket(unsigned char *buffer, int buflen, uint64_t timestamp)
{
    if(m_pVideoDecode)
    {
        m_videoPacket.buffer = buffer;
        m_videoPacket.length = buflen;
        m_videoPacket.pts = timestamp;

        //LOG_PrintWarn("sendVideoPacket CALL");

        return m_pVideoDecode->putPacket(&m_videoPacket);
    }
    return false;
}

bool RtspClientStream::sendAudioPacket(unsigned char *buffer, int buflen)
{
    if(m_pAudioDecode)
    {
        m_audioPacket.buffer = buffer;
        m_audioPacket.length = buflen;
        
        return m_pAudioDecode->putPacket(&m_audioPacket);
    }

    return false;
}


}

